<!--文章读取页面,只能查看文章内容-->
<template>
  <div>
    <el-row>
      <el-col :span="3"
              v-show="showCatalog">
        <div>
          <div>目录</div>
          <el-button type="text" size="mini" @click="expandAll">全部展开</el-button>
          <el-button type="text" size="mini" @click="unexpandAll">全部关闭</el-button>
          <el-button type="text" size="mini" @click="expandChange">反转</el-button>
          <!--用树形结构展示目录-->
          <el-tree ref="tree" :data="treeData"
                   :indent="10"
                   :props="defaultProps"
                   node-key="id"
                   :highlight-current="true"
                   :expand-on-click-node="false"
                   @node-click="handleNodeClick"></el-tree>
        </div>
      </el-col>
      <!--目录隐藏按钮-->
      <el-col :span="1" style="width: 15px">
        <i v-show="showCatalog" style="cursor: pointer" class="el-icon-s-fold" @click="foldCatalog"></i>
        <i v-show="!showCatalog" style="cursor: pointer" class="el-icon-s-unfold" @click="unfoldCatalog"></i>
        <span style="font-size: 12px">目录</span>
      </el-col>
      <el-col :span="textAreaSpan">
        <!--文章标题及作者信息-->
        <div style="text-align: center" >
          <h1 style="margin: 0">{{articleAllInfo.title}}</h1>
          文章作者:<el-tag style="cursor: pointer" type="mini" @click="goToAuthorPage(articleAllInfo.username)">{{articleAllInfo.username}}</el-tag>
          <!--关注图标-->
          <el-button  v-if="!isFollow" type="text" @click="processFollow">
            <i class="el-icon-plus"></i>
            关注<el-image style="width: 13px;height: 13px" :src="require('@/assets/img/unlike.png')"></el-image>
          </el-button>
          <el-button v-if="isFollow"  type="text" @click="processFollow">
            <i class="el-icon-minus"></i>
            取关<el-image style="width: 13px;height: 13px" :src="require('@/assets/img/like.png')"></el-image>
          </el-button>
        </div>
        <!--工具栏-->
        <div style="text-align: left" >
          <el-button v-if="isEdit" type="text" @click="editText(articleId)">编辑</el-button>
          <!--点赞图标-->
          <el-button  v-if="!isLike" type="text" @click="processLike">
            未点赞<el-image style="width: 13px;height: 13px" :src="require('@/assets/img/unlike.png')"></el-image>
          </el-button>
          <el-button v-if="isLike"  type="text" @click="processLike">
            已点赞<el-image style="width: 13px;height: 13px" :src="require('@/assets/img/like.png')"></el-image>
          </el-button>
          <!--收藏-->
          <el-button v-if="!isStar"  type="text" @click="processStar">
            未收藏<i class="el-icon-star-off"></i>
          </el-button>
          <el-button v-if="isStar" type="text" @click="processStar">
            已收藏<i class="el-icon-star-on"></i>
          </el-button>
          <!--分享-->
          <el-button type="text" @click="goToShare">
            <i class="el-icon-share"></i>
            分享
          </el-button>
          <el-dialog title="文章分享" :visible.sync="qrCodeModalVisible">
            <el-row>
              <el-col :xs="24"
                      :sm="12"
                      :md="8"
                      :lg="6">
                <div id="qrcode"></div>
              </el-col>
              <el-col :xs="24"
                      :sm="12"
                      :md="8"
                      :lg="6">
                <div id="qrcode-text">
                  <div>
                    <textarea style="width: 100%" v-model="url" placeholder="网址"></textarea>
                    <el-button type="success" @click="copyThisUrl">复制</el-button>
                  </div>
                </div>
              </el-col>
            </el-row>
            <span slot="footer" class="dialog-footer">
               <el-button @click="closeDisLogQrCode">关闭</el-button>
            </span>
          </el-dialog>
          <!--评论-->
          <el-button type="text" @click="goToComment">
            <i class="el-icon-chat-line-round"></i>
            评论
          </el-button>
        </div>

        <!--实时渲染  类名缺一不可-->
        <div class="ql-container ql-snow">
          <div class="ql-editor" v-html="previewContent" style="height: 615px;overflow-y: auto"></div>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import QRCode from 'qrcodejs2';
import {
  getQuillTextById
} from "@/api/quillTextApi";
import {getUserName} from "@/api/token";
import {
  add_articleLikeDetailInfo,
  deleteLikeByUserNameAndArticleId,
  get_IsLike
} from "@/api/likeDetailsInfo";
import {
  add_articleCollectionDetailInfo,
  deleteStarByUserNameAndArticleId,
  get_IsStar
} from "@/api/starDetailsInfo";
import {
  add_followingDetailInfo,
  deleteFollowingByUserNameAndFolloweeName,
  get_IsFollowing
} from "@/api/followingDetails";
import {copyTextToClipboard} from "@/plugins/commen";
export default {
  // props:['articleId'],
  data() {
    return {
      url: '',
      /**
       * 二维码弹窗
       */
      qrCodeModalVisible:false,
      /**
       * 二维码实例
       */
      qrCodeInstance: null,
      isFollow:false,
      isLike:false,
      isStar:false,
      /**
       * 是否可编辑
       */
      isEdit:false,
      searchQuery:'',
      previewContent:'',
      articleId:'',
      articleAllInfo:'',
      textAreaSpan:23,
      showCatalog:false,
      //tree
      isExpandedAll: true,
      treeData: [
      ],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      // tree end

      // 匹配的文本
      matchText:''
    };
  },
  created() {
    this.url = window.location.href
  },
  mounted() {
    // this.goToShare()

    // 上一页跳过来的文章id
    let articleId = this.$route.query['articleId'];
    this.articleId = articleId
    /**
     * 必须先获取  后序的才能执行   而异步就造成看后序的内容发送出错  其他操作放在axios的回调当中
     */
    this.getTextById(articleId)
    // this.getIsFollow()
    // this.judgeIsEdit()
  },
  methods: {
    /**
     * 跳转到作者页面
     */
    goToAuthorPage(authorName){
      this.$router.push({
        path: '/index/author-info',
        query: {
          authorName:authorName
        }
      })
    },
    /**
     * 判断是否可编辑
     */
    judgeIsEdit(){
      let loginUserName = getUserName()
      let articleAuthor = this.articleAllInfo.username
      this.isEdit = loginUserName === articleAuthor;
      // console.log('是否可编辑',this.isEdit)
    },
    /**
     * 折叠目录
     */
    foldCatalog(){
      this.showCatalog = !this.showCatalog
      this.textAreaSpan = 23
    },
    /**
     * 展开目录
     */
    unfoldCatalog(){
      this.showCatalog = !this.showCatalog
      this.$nextTick(()=>{
        this.textAreaSpan = 20
      })
      this.$forceUpdate()
    },
    /**
     * 获取文章内容
     * @param id
     */
    async getTextById(id) {
      await getQuillTextById(id).then((res)=>{
        this.articleAllInfo = res.data
        // 获取数据成功后的其他操作
        this.getOtherInfo()
        this.judgeIsEdit()
        this.previewContent = res.data.content
        // console.log(this.previewContent)
        this.treeData = this.getCatalogFromStr(this.previewContent)
        this.treeData = this.convertToTree(this.treeData)

      }).catch((err)=>{

      })
    },
    /**
     * 从字符串中获取目录
     * @param str
     * @returns {*[]}
     */
    getCatalogFromStr(str) {
      let reg = /<h[1-6]>(.*?)<\/h[1-6]>/g
      let arr = str.match(reg)
      // console.log( '所有h目录的字符串数组',arr) // ['<h1>接口名称：登录接口</h1>','','','']等

      // 转arr转扁平树形结构
      let tree = []
      arr.forEach(item => {
        // 将item转为dom
        let dom = document.createElement('div')
        dom.innerHTML = item
        // console.log( 'dom',dom.innerText)
        // 只取标题文本进行定位
        let hxxText = dom.innerText

        let reg = /<h([1-6])>(.*?)<\/h[1-6]>/
        // console.log( '匹配结果',reg)
        let res = reg.exec(item)
        let obj = {
          text: hxxText,
          level: parseInt(res[1]),
          // children: []
        }
        tree.push(obj)
      })
      return tree
    },
    /**
     * 将目录数组转换为树形结构
     * @param data
     * @returns {*[]}
     */
    convertToTree(data) {
      const tree = [];
      let currentParent = null;

      data.forEach((item ,index)=> {
        if (item.level === 1) {
          // 遇到 level 为 1 的，创建新的树节点并作为父节点
          currentParent = {
            label: item.text,
            value: item.text,
            id: index,
            children: []
          };
          tree.push(currentParent);
        }
        else {
          let parent = currentParent;
          while (parent && parent.level < item.level) {
            if (!parent.children) {
              parent.children = [];
            }
            parent = parent.children[parent.children.length - 1];
          }
          if (!parent.children) {
            parent.children = [];
          }
          // 根据 level 创建对应的节点层级
          const newNode = {
            label: item.text,
            value: item.text,
            id: index,
            children: []
          };
          if (item.level === 2) {
            parent.children.push(newNode);
          } else if (item.level === 3) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            if (!secondLevelParent.children) {
              secondLevelParent.children = [];
            }
            secondLevelParent.children.push(newNode);
          } else if (item.level === 4) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            const thirdLevelParent = secondLevelParent.children[secondLevelParent.children.length - 1];
            if (!thirdLevelParent.children) {
              thirdLevelParent.children = [];
            }
            thirdLevelParent.children.push(newNode);
          }
        }
      });

      return tree;
    },
    /**
     * 目录展开状态切换
     */
    expandChange() {
      const tree = this.$refs.tree
      // console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = !nodes[key].expanded
      })
    },
    /**
     * 展开所有目录
     */
    expandAll() {
      const tree = this.$refs.tree
      // console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = tree
      })
    },
    /**
     * 关闭所有目录
     */
    unexpandAll() {
      const tree = this.$refs.tree
      // console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = false
      })
    },

    /**
     * 点击目录
     * @param data
     * @param node
     */
    handleNodeClick(data,node) {
      let level = 1;
      let parent = node.parent;
      while (parent) {
        level++;
        parent = parent.parent;
      }
      level--
      // console.log(`点击的节点是第${level}级节点，节点信息：`, data);

      let clickText = data.label
      // console.log('标签',clickText)
      // 为了精确定位目录   加上类似h1这样的标签  防止定位到普通文本
      clickText = `<h${level}>${clickText}</h${level}>`
      // console.log(clickText)
      this.searchQuery = clickText
      this.searchInEditor()
    },
    /**
     * 处理所有文本  将数据库的html文本的h标签中多余的标签处理掉  以更好的去目录进行匹配
     * @param str
     */
    processAllText(str) {
      let parser = new DOMParser();
      let doc = parser.parseFromString(str, 'text/html');

      let hElements = doc.getElementsByTagName('h1');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }

      hElements = doc.getElementsByTagName('h2');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h3');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h4');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h5');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h6');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      // 获取doc.documentElement的body
      let body = doc.body;
      let result = body.innerHTML;
      // 去掉换行符与空格
      // result = result.replace(/\s/g, '');
      result = result.replace(/\n/g, '');
      // console.log('处理后的全文本',result);
      return result
    },
    /**
     * 点击目录滚动到指定位置
     */
    searchInEditor() {
      let searchText = this.searchQuery
      // 类似这样的字符  <h1>接口名称：登录接口</h1>
      console.log('搜索目录',searchText)
      /**
       * 可能包含的是    <h1><span>接口名称：登录接口</>span></h1>   这样的话allText.indexOf就不能匹配   又不能只匹配文本  导致目录定位到普通文本
       * 所以需要将搜索文本加上类似h1这样的标签  将h1标签与文本之间的标签用全正则匹配
       *   正则表达式  /<h[1-6]>(.*?)<\/h[1-6]>/g  如将<h1><span>接口名称：登录接口</>span></h1>
       * 类似这样的字符  <h1>接口名称：登录接口</h1>
       * @type {string}
       */
      let allText = this.previewContent
      allText = this.processAllText(allText)
      if(!searchText) return null
      let index = allText.indexOf(searchText)
      console.log(index)
      if (index === -1) return null
      let before = allText.substring(0, index);
      let match = allText.substring(index, index + searchText.length);
      let after = allText.substring(index + searchText.length);
      // 全部文本重新渲染   达到定位效果
      this.matchText = '<span class="clickEle" style="background-color: rgba(232,232,50,0)">' + match + '</span>'
      // 事先复制一份数据  用于恢复
      let previewContentCopy = JSON.parse(JSON.stringify(this.previewContent))
      this.previewContent = before + this.matchText + after;

      // 卧槽  这样就简单多了
      this.$nextTick(()=>{
        document.querySelector('.clickEle').scrollIntoView({})
        // 定位完之后  将文本恢复至数据库状态
        this.previewContent = previewContentCopy
      })
      // // 滚动效果已经实现   改变top即可
      // let quillEditorContainer = document.querySelector('.ql-editor ')
      // let topNum = 200  // 微调
      // this.$nextTick(() => {
      //   quillEditorContainer.scrollTo({
      //     top: topNum,
      //     behavior: 'smooth'
      //   });
      // })
    },

    /**
     * 再次编辑文章
     * @param articleId
     */
    editText(articleId){
      // 跳转编辑页面   并将文章信息传递过去
      this.$router.push({
        path:'/index/edit-text',
        query:{
          articleAllInfo:this.articleAllInfo
        }
      })
    },

    /**
     * 处理关注
     */
    processFollow(){
      this.isFollow= !this.isFollow
      if(this.isFollow){
        add_followingDetailInfo({
          // 当前登录用户
          userName:getUserName(),
          // 被关注的人
          followingUserName:this.articleAllInfo.username
        }).then((res)=>{
          // console.log(res)
        }).catch((err)=>{
          console.log(err)
        })
      }else {
        deleteFollowingByUserNameAndFolloweeName({
          // 当前登录用户
          userName:getUserName(),
          // 被关注的人
          followingUserName:this.articleAllInfo.username
        }).then((res)=>{
        })
      }
    },
    /**
     * 处理喜欢
     */
    processLike(){
      this.isLike= !this.isLike
      // 喜欢就新增  不喜欢就删除
      if(this.isLike){
        add_articleLikeDetailInfo({
          liker:getUserName(),
          articleId:this.articleAllInfo.articleId
        }).then((res)=>{
          // console.log(res)
        }).catch((err)=>{
          console.log(err)
        })
      }else {
        deleteLikeByUserNameAndArticleId({
          liker:getUserName(),
          articleId:this.articleAllInfo.articleId
        }).then((res)=>{
          // console.log(res)
        }).catch((err)=>{
          console.log(err)
        })
      }


    },
    /**
     * 处理收藏
     */
    processStar(){
      this.isStar= !this.isStar
      if(this.isStar){
        add_articleCollectionDetailInfo({
          collector:getUserName(),
          articleId:this.articleAllInfo.articleId
        }).then((res)=>{
          // console.log(res)
        }).catch((err)=>{
          console.log(err)
        })
      }else {
        deleteStarByUserNameAndArticleId({
          collector:getUserName(),
          articleId:this.articleAllInfo.articleId
        }).then((res)=>{
        })
      }
    },

    /**
     * 获取是否点赞
     * 根据当前登录的用户名userName,查询是否点赞此文章articleId
     */
    getIsLike() {
      let userName = getUserName()
      let getForm = {
        liker: userName,
        articleId: this.articleAllInfo.articleId
      }
      // console.log('查询参数',this.articleAllInfo)
      if(userName){
        get_IsLike(getForm).then((res)=>{
          this.isLike = res.data
          // console.log('是否点赞',this.isLike)
        }).catch((err)=>{
          console.log(err)
        })
      }
    },
    /**
     * 获取是否收藏
     */
    getIsStar() {
      let userName = getUserName()
      let getForm = {
        collector: userName,
        articleId: this.articleAllInfo.articleId
      }
      // console.log('查询参数',this.articleAllInfo)
      if(userName){
        get_IsStar(getForm).then((res)=>{
          this.isStar = res.data
          // console.log('是否收藏',this.isStar)
        }).catch((err)=>{
          console.log(err)
        })
      }
    },
    /**
     * 获取是否关注
     */
    getIsFollow() {
      let userName = getUserName()
      let getForm = {
        // 当前登录用户
        userName:getUserName(),
        // 被关注的人
        followingUserName:this.articleAllInfo.username
      }
      // console.log('查询参数',this.articleAllInfo)
      if(userName){
        get_IsFollowing(getForm).then((res)=>{
          this.isFollow = res.data
          // console.log('是否关注',this.isFollow)
        }).catch((err)=>{
          console.log(err)
        })
      }
    },
    /**
     * 获取其他信息 关注、点赞、收藏
     */
    getOtherInfo(){
      this.getIsFollow()
      this.getIsLike()
      this.getIsStar()
    },
    /**
     * 打开分享二维码
     */
    goToShare(){
      this.qrCodeModalVisible = true;
      // 生成此网站的二维码
      this.$nextTick(()=>{
        if(!this.qrCodeInstance){
          this.qrCodeInstance = new QRCode('qrcode',  {
            text: this.url,
            width: 150,
            height: 150,
          });
        }
      })
    },
    /**
     *  关闭二维码
     */
    closeDisLogQrCode(){
      this.qrCodeModalVisible = false;
    },
    /**
     * 复制链接
     */
    copyThisUrl(){
      copyTextToClipboard(this.url)
    },
    goToComment(){

    }
  },
  beforeDestroy() {

  }
};
</script>

<style>
#qrcode {

}
/* 可以根据需要添加一些样式 */
.ql-toolbar {
  border: 1px solid #ccc;
}

.ql-container {
  border: 1px solid #ccc;
}

.el-tag + .el-tag {
  margin-left: 10px;
}
.button-new-tag {
  margin-left: 10px;
  height: 32px;
  line-height: 30px;
  padding-top: 0;
  padding-bottom: 0;
}
.input-new-tag {
  width: 90px;
  margin-left: 10px;
  vertical-align: bottom;
}

</style>